home *** CD-ROM | disk | FTP | other *** search
- ; Simple "Moon Lander" game.
- ;
- ; Randall Hyde
- ; 2/8/96
- ;
- ; This program is an example of a trivial little "moon lander"
- ; game that simulates a Lunar Module setting down on the Moon's
- ; surface. At time T=0 the spacecraft's velocity is 1000 ft/sec
- ; downward, the craft has 1000 units of fuel, and the craft is
- ; 10,000 ft above the moon's surface. The pilot (user) can
- ; specify how much fuel to burn at each second.
- ;
- ; Note that all calculations are approximate since everything is
- ; done with integer arithmetic.
-
-
- ; Some important constants
-
- InitialVelocity = 1000
- InitialDistance = 10000
- InitialFuel = 250
- MaxFuelBurn = 25
-
- MoonsGravity = 5 ;Approx 5 ft/sec/sec
- AccPerUnitFuel = -5 ;-5 ft/sec/sec for each fuel unit.
-
-
- .xlist
- include stdlib.a
- includelib stdlib.lib
- .list
-
- .386 ;Comment out these two statements
- option segment:use16 ; if you are not using an 80386.
-
- dseg segment para public 'data'
-
- ; Current distance from the Moon's Surface:
-
- CurDist word InitialDistance
-
- ; Current Velocity:
-
- CurVel word InitialVelocity
-
- ; Total fuel left to burn:
-
- FuelLeft word InitialFuel
-
-
- ; Amount of Fuel to use on current burn.
-
- Fuel word ?
-
- ; Distance travelled in the last second.
-
- Dist word ?
-
- dseg ends
-
- cseg segment para public 'code'
- assume cs:cseg, ds:dseg
-
- ; GETI- Reads an integer variable from the user and returns its
- ; its value in the AX register. If the user entered garbage,
- ; this code will make the user re-enter the value.
-
- geti textequ <call _geti>
- _geti proc
- push es
- push di
- push bx
-
- ; Read a string of characters from the user.
- ;
- ; Note that there are two (nested) loops here. The outer loop
- ; (GetILp) repeats the getsm operation as long as the user
- ; keeps entering an invalid number. The innermost loop (ChkDigits)
- ; checks the individual characters in the input string to make
- ; sure they are all decimal digits.
-
- GetILp: getsm
-
- ; Check to see if this string contains any non-digit characters:
- ;
- ; while (([bx] >= '0') and ([bx] <= '9') bx := bx + 1;
- ;
- ; Note the sneaky way of turning the while loop into a
- ; repeat..until loop.
-
- mov bx, di ;Pointer to start of string.
- dec bx
- ChkDigits: inc bx
- mov al, es:[bx] ;Fetch next character.
- IsDigit ;See if it's a decimal digit.
- je ChkDigits ;Repeat if it is.
-
- cmp al, 0 ;At end of string?
- je GotNumber
-
- ; Okay, we just ran into a non-digit character. Complain and make
- ; the user reenter the value.
-
- free ;Free space malloc'd by getsm.
- print
- byte cr,lf
- byte "Illegal unsigned integer value, "
- byte "please reenter.",cr,lf
- byte "(no spaces, non-digit chars, etc.):",0
- jmp GetILp
-
-
- ; Okay, ES:DI is pointing at something resembling a number. Convert
- ; it to an integer.
-
- GotNumber: atoi
- free ;Free space malloc'd by getsm.
-
- pop bx
- pop di
- pop es
- ret
- _geti endp
-
-
-
-
-
- ; InitGame- Initializes global variables this game uses.
-
- InitGame proc
- mov CurVel, InitialVelocity
- mov CurDist, InitialDistance
- mov FuelLeft, InitialFuel
- mov Dist, 0
- ret
- InitGame endp
-
-
- ; DispStatus- Displays important information for each
- ; cycle of the game (a cycle is one second).
-
- DispStatus proc
- printf
- byte cr,lf
- byte "Distance from surface: %5d",cr,lf
- byte "Current velocity: %5d",cr,lf
- byte "Fuel left: %5d",cr,lf
- byte lf
- byte "Dist travelled in the last second: %d",cr,lf
- byte lf,0
- dword CurDist, CurVel, FuelLeft, Dist
- ret
- DispStatus endp
-
-
- ; GetFuel- Reads an integer value representing the amount of fuel
- ; to burn from the user and checks to see if this value
- ; is reasonable. A reasonable value must:
- ;
- ; * Be an actual number (GETI handles this).
- ; * Be greater than or equal to zero (no burning
- ; negative amounts of fuel, GETI handles this).
- ; * Be less than MaxFuelBurn (any more than this and
- ; you have an explosion, not a burn).
- ; * Be less than the fuel left in the Lunar Module.
-
- GetFuel proc
- push ax
-
- ; Loop..endloop structure that reads an integer input and terminates
- ; if the input is reasonable. It prints a message an repeats if
- ; the input is not reasonable.
- ;
- ; loop
- ; get fuel;
- ; if (fuel < MaxFuelBurn) then break;
- ; print error message.
- ; endloop
- ;
- ; if (fuel > FuelLeft) then
- ;
- ; fuel = fuelleft;
- ; print appropriate message.
- ;
- ; endif
-
- GetFuelLp: print
- byte "Enter amount of fuel to burn: ",0
- geti
- cmp ax, MaxFuelBurn
- jbe GoodFuel
-
- print
- byte "The amount you've specified exceeds the "
- byte "engine rating,", cr, lf
- byte "please enter a smaller value",cr,lf,lf,0
- jmp GetFuelLp
-
- GoodFuel: mov Fuel, ax
- cmp ax, FuelLeft
- jbe HasEnough
- printf
- byte "There are only %d units of fuel left.",cr,lf
- byte "The Lunar module will burn this rather than %d"
- byte cr,lf,0
- dword FuelLeft, Fuel
-
- mov ax, FuelLeft
- mov Fuel, ax
-
- HasEnough: mov ax, FuelLeft
- sub ax, Fuel
- mov FuelLeft, ax
- pop ax
- ret
- GetFuel endp
-
-
-
- ; ComputeStatus-
- ;
- ; This routine computes the new velocity and new distance based on the
- ; current distance, current velocity, fuel burnt, and the moon's
- ; gravity. This routine is called for every "second" of flight time.
- ;
- ; note:
- ;
- ; Distance Travelled = Acc*T*T/2 + Vel*T (note: T=1, so it goes away).
- ; Acc = MoonsGravity + Fuel * AccPerUnitFuel
- ;
- ; New Velocity = Acc*T + Prev Velocity
- ;
- ; This code should really average these values over the one second
- ; time period, but the simulation is so crude anyway, there's no
- ; need to really bother.
-
- ComputeStatus proc
- push ax
- push bx
- push dx
-
- ; First, compute the acceleration value based on the fuel burnt
- ; during this second (Acc = Moon's Gravity + Fuel * AccPerUnitFuel).
-
- mov ax, Fuel ;Compute
- mov dx, AccPerUnitFuel ; Fuel*AccPerUnitFuel
- imul dx
-
- add ax, MoonsGravity ;Add in Moon's gravity.
- mov bx, ax ;Save Acc value.
-
- ; Now compute the new velocity (V=AT+V)
-
- add ax, CurVel ;Compute new velocity
- mov CurVel, ax
-
- ; Next, compute the distance travelled (D = 1/2 * A * T^2 + VT +D)
-
- sar bx, 1 ;Acc/2
- add ax, bx ;Acc/2 + V (T=1!)
- mov Dist, ax ;Distance Travelled.
- neg ax
- add CurDist, ax ;New distance.
-
- pop dx
- pop bx
- pop ax
- ret
- ComputeStatus endp
-
-
- ; GetYorN- Reads a yes or no answer from the user (Y, y, N, or n).
- ; Returns the character read in the al register (Y or N,
- ; converted to upper case if necessary).
-
- GetYorN proc
- getc
- ToUpper
- cmp al, 'Y'
- je GotIt
- cmp al, 'N'
- jne GetYorN
- GotIt: ret
- GetYorN endp
-
-
-
-
- Main proc
- mov ax, dseg
- mov ds, ax
- mov es, ax
- meminit
-
- MoonLoop: print
- byte cr,lf,lf
- byte "Welcome to the moon lander game.",cr,lf,lf
- byte "You must manuever your craft so that you touch"
- byte "down at less than 10 ft/sec",cr,lf
- byte "for a soft landing.",cr,lf,lf,0
-
- call InitGame
-
- ; The following loop repeats while the distance to the surface is greater
- ; than zero.
-
- WhileStillUp: mov ax, CurDist
- cmp ax, 0
- jle Landed
-
- call DispStatus
- call GetFuel
- call ComputeStatus
- jmp WhileStillUp
-
- Landed: cmp CurVel, 10
- jle SoftLanding
-
- printf
- byte "Your current velocity is %d.",cr,lf
- byte "That was just a little too fast. However, as a "
- byte "consolation prize,",cr,lf
- byte "we will name the new crater you just created "
- byte "after you.",cr,lf,0
- dword CurVel
-
- jmp TryAgain
-
- SoftLanding: printf
- byte "Congrats! You landed the Lunar Module safely at "
- byte "%d ft/sec.",cr,lf
- byte "You have %d units of fuel left.",cr,lf
- byte "Good job!",cr,lf,0
- dword CurVel, FuelLeft
-
- TryAgain: print
- byte "Do you want to try again (Y/N)? ",0
- call GetYorN
- cmp al, 'Y'
- je MoonLoop
-
- print
- byte cr,lf
- byte "Thanks for playing! Come back to the moon again sometime"
- byte cr,lf,lf,0
-
-
- Quit: ExitPgm ;DOS macro to quit program.
- Main endp
-
- cseg ends
-
- sseg segment para stack 'stack'
- stk byte 1024 dup ("stack ")
- sseg ends
-
- zzzzzzseg segment para public 'zzzzzz'
- LastBytes byte 16 dup (?)
- zzzzzzseg ends
- end Main
-